#include<iostream>
using namespace std;
#include<cstdio>
#include<cstdlib>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstring>
const int basesize=1024;
const int argvnum=1024;
const int envnum=1024;
char * gargv[argvnum];
int gargc=0;
int lastcode=0;
char* genv[envnum];
char pwd[basesize];
char pwdenv[basesize];
string getUserName()
{
  string name=getenv("USER");
  return name.empty()?"none":name;
}

string getHostName()
{
  string name=getenv("HOSTNAME");
  return name.empty()?"none":name;
}
string Getpwd()
{
  if(getcwd(pwd,sizeof(pwd))==nullptr)return  "None";//返回工作路径指针
  snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);
  putenv(pwdenv);//添加环境变量
  return pwd;
}
string LastDir()
{
  string curr=Getpwd();
  if(curr=="/"||curr=="None")return curr;
  size_t pos=curr.rfind("/");
  if(pos==string::npos)return curr;
  return curr.substr(pos+1);//获取路径
}
string MakeCommandLine()//打印命令前面的框架
{
  char command_line[basesize];
  snprintf(command_line,basesize,"[%s@%s %s]#",getUserName().c_str(),getHostName().c_str(),LastDir().c_str());
  return command_line;
}
void printCommandLine()//命令提示符
{
  printf("%s",MakeCommandLine().c_str());
  fflush(stdout);//直接放出缓冲区
}
bool GetCommmandLine(char command_buffer[],int size)//获取命令
{
//把用户的命令变成一条完整的字符串

  char* result=fgets(command_buffer,size,stdin);//流输入的数据存在command_buffer
  if(!result)
  {
    return false;
  }
  command_buffer[strlen(command_buffer)+1]=0;//把这个\n变成\0
  if(strlen(command_buffer)==0)return false;
  return true;

}
void ParseCommmandLine(char command_buffer[],int len)//分析命令
{

  (void)len;
  memset(gargv,0,sizeof(gargv));//把这个gargv用0的类型来覆盖
  gargc=0;
  const char*sep=" ";
  gargv[gargc++]=strtok(command_buffer,sep);//以空格当分割符
  while((bool)(gargv[gargc++]==strtok(nullptr,sep)));//继续切割其他的命令
  gargc--;

}
void debug()
{
  printf("agrc:%d\n",gargc);
  for(  int i=0;gargv[i];i++)
  {
    printf("argv[%d]:%s",i,gargv[i]);
  }
}
//子进程执行命令

bool ExecuteCommand()
{
  pid_t id=fork();
  if(id<0)return false;
  else if(id==0)
  {
    execvpe(gargv[0],gargv,genv);
    exit(1);
  }
  int status=0;
  pid_t rid=waitpid(id,&status,0);
  if(rid>0)
  {
    if(WIFEXITED(status))
    {
      lastcode=WEXITSTATUS(status);
    }else 
    {
      lastcode=100;
    }
    return true;
  }
  return false;
}

void AddEnv(const char *item)
{
  int index=0;
  while(genv[index])
  {
    index++;
  }
  genv[index]=(char*)malloc(strlen(item)+1);
  strncpy(gargv[index],item,strlen(item)+1);
  genv[++index]=nullptr;
}
void InitEnv()
{
  extern char** environ;
  int index=0;
  while(environ[index])
  {
    genv[index]=(char*)malloc(strlen(environ[index])+1);//strlen是不计算这个空格的
    strncpy(genv[index],environ[index],strlen(environ[index])+1);
    index++;
  }
  genv[index]=nullptr;
}
bool CheckAndExcbulitCommand()
{
  if(strcmp(gargv[0],"cd")==0)
  {
    if(gargc==2)
    {
      chdir(gargv[1]);
      lastcode=0;
    }else
    {
      lastcode=1;
    }
    return true;
  }else if(strcmp(gargv[0],"export")==0)
  {
    if(gargc==2)
    {
      AddEnv(gargv[1]);
      lastcode=0;
    }else 
    {
      lastcode=2;
    }
    return true;
  }else if(strcmp(gargv[0],"env")==0)
  {
    for(int i=0;genv[i];i++)
    {
      printf("%s\n",genv[i]);

    }
    lastcode=0;
    return true;
  }else if(strcmp(gargv[0], "echo") == 0)
    {
        if(gargc == 2)
        {
            // echo $?
            // echo $PATH
            // echo hello
            if(gargv[1][0] == '$')
            {
                if(gargv[1][1] == '?')
                {
                    printf("%d\n", lastcode);
                    lastcode = 0;
                }
            }
            else
            {
                printf("%s\n", gargv[1]);
                lastcode = 0;
            }
        }
        else
        {
            lastcode = 3;
        }
        return true;
    }
    return false;
}
int main()
{
  InitEnv();
  char command_buffer[basesize];
  while(true)
  {
    printCommandLine();
    if(!GetCommmandLine(command_buffer,basesize))//获取命令
    {
      continue;
    }
    ParseCommmandLine(command_buffer,strlen(command_buffer));//分析命令
    if(CheckAndExcbulitCommand())
    {
      continue;
    }
    ExecuteCommand();//执行命令
  }
  return 0;
}
